#include <stdio.h>

#include <memory>
#include <cppunit/extensions/TestFactoryRegistry.h>
#include <cppunit/ui/text/TestRunner.h>
#include <cppunit/CompilerOutputter.h>
#include <cppunit/TestCase.h>
#include <cppunit/extensions/HelperMacros.h>

#include <GMClient.hh>
#include <GMRobot.hh>

// Constantes
const std::string kSerialPathTest = "serial_teste";


//////////////////////////////////////////////////
// Teste realizados com o GMCliente
class GMClientTestCase : public CppUnit::TestCase
{
    CPPUNIT_TEST_SUITE( GMClientTestCase );
    CPPUNIT_TEST( getField );
    CPPUNIT_TEST( getWorld );
    CPPUNIT_TEST( setField );
    CPPUNIT_TEST( setWorld );
    CPPUNIT_TEST_SUITE_END();

    GMClient client;
    void worldSendAndReceive ();
    void fieldSendAndReceive ();
    void getField();
    void setField();
    void getWorld();
    void setWorld();
public:
    void			setUp ();
};


CPPUNIT_TEST_SUITE_NAMED_REGISTRATION( GMClientTestCase, "GMClientTestCase" );


void GMClientTestCase::setUp ()
{
    CPPUNIT_ASSERT( client.Init("localhost", 12345) == 0 );
}

void
GMClientTestCase::getField()
{
    std::vector<float> field(kFieldVectorLength);
    client.getField(field);
}

void
GMClientTestCase::setField()
{
    std::vector<float> field(kFieldVectorLength, 42);
    client.setField(field);
}

void
GMClientTestCase::getWorld()
{
    std::vector<float> world(kWorldVectorLength);
    client.getWorld(world);
}

void
GMClientTestCase::setWorld()
{
    std::vector<float> world(kWorldVectorLength, 24);
    client.setWorld(world);
}

void
GMClientTestCase::worldSendAndReceive ()
{
    // Testando com um valor de 2
    std::vector<float> world_sent(kWorldVectorLength, 2);
    std::vector<float> world_received(kWorldVectorLength, 0);

    client.setWorld( world_sent );
    client.getWorld( world_received );

}

void
GMClientTestCase::fieldSendAndReceive ()
{
    // Testando com um valor de 2
    std::vector<float> field_sent(kFieldVectorLength, 2);
    std::vector<float> field_received(kFieldVectorLength, 0);

    client.setField( field_sent );
    client.getField( field_received );

}
/////////////////////////////////////////////////////



////////////////////////////////////////////////////
// Testes realizados com a classe GMRobot
class GMRobotTestCase : public CppUnit::TestCase
{
    CPPUNIT_TEST_SUITE( GMRobotTestCase );
    CPPUNIT_TEST( SetVel );
    CPPUNIT_TEST( Kick );
    CPPUNIT_TEST( DribbleEnable );    
    CPPUNIT_TEST_SUITE_END();

    GMRobot *robot_;
    void SetVel();
    void Kick();
    void DribbleEnable();
    void			robotSetVelAndReadSerial ();
public:
    void			setUp ();
};


CPPUNIT_TEST_SUITE_NAMED_REGISTRATION( GMRobotTestCase, "GMRobotTestCase" );

void
GMRobotTestCase::setUp()
{
    robot_ = new GMRobot( 1, "BA0", "localhost", 12345 );
}

void
GMRobotTestCase::SetVel()
{
    CPPUNIT_ASSERT( robot_->SetVel(0.2, 0.45, 0.12) == 0 );
}

void
GMRobotTestCase::Kick()
{
    CPPUNIT_ASSERT( robot_->Kick(1) == 0 );
}

void
GMRobotTestCase::DribbleEnable()
{
    CPPUNIT_ASSERT( robot_->DribbleEnable(true) == 0 );
    CPPUNIT_ASSERT( robot_->DribbleEnable(false) == 0 );
}

///////////////////////////////////////////////////

CppUnit::Test *suite()
{
    
    CppUnit::TestFactoryRegistry &registry =
        CppUnit::TestFactoryRegistry::getRegistry();


    registry.registerFactory(
        &CppUnit::TestFactoryRegistry::getRegistry( "GMClientTestCase" ) );
     registry.registerFactory(
         &CppUnit::TestFactoryRegistry::getRegistry( "GMRobotTestCase" ) );
    return registry.makeTest();
}



int
main( int argc, char* argv[] )
{
    // if command line contains "-selftest" then this is the post build check
    // => the output must be in the compiler error format.
    bool selfTest = (argc > 1)  &&
        (std::string("-selftest") == argv[1]);


    CppUnit::TextUi::TestRunner runner;
    runner.addTest( suite() );   // Add the top suite to the test runner


    selfTest = true;
    if ( selfTest )
    { // Change the default outputter to a compiler error format outputter
        // The test runner owns the new outputter.
        runner.setOutputter( CppUnit::CompilerOutputter::defaultOutputter(
                                 &runner.result(),
                                 std::cerr ) );
    }


    // Run the test.
    bool wasSucessful = runner.run( "" );


    // Return error code 1 if any tests failed.
    return wasSucessful ? 0 : 1;
}
